// campus_login_manager.cpp
#include "campus_login_manager.h"
#include"campus_login_administer.h"
// 构造函数：注入服务器和SQL连接依赖
CampusLoginManager::CampusLoginManager(CampusWholeServer* whole_server, CampusSqlConnector* sql_connector) :
     whole_server_(whole_server), sql_connector_(sql_connector) 
{
    if (whole_server_ == nullptr || sql_connector_ == nullptr) {
        CampusLogger::warn("CampusLoginManager init fail: dependency is null");
    }

    //初始化login_administer
    CampusLoginAdminister::setOnlineMap(&uid_hdl_map_);
}

CampusLoginManager::~CampusLoginManager()
{
}

// -------------------------- 业务回调接口实现（供WholeManager转发）--------------------------
void CampusLoginManager::handleLoginSalt(websocketpp::connection_hdl hdl, json JMsg) {
    if (!JMsg.contains("uid")) {
        CampusLogger::warn("handleLoginSalt: missing 'uid' in message");
        return;
    }
    std::string uid = JMsg["uid"];
    doLoginSalt(hdl, uid);
}

void CampusLoginManager::handleLogin(websocketpp::connection_hdl hdl, const json JMsg) {
    if (!JMsg.contains("uid") || !JMsg.contains("hash")) {
        CampusLogger::warn("handleLogin: missing 'uid' or 'hash' in message");
        return;
    }
    std::string uid = JMsg["uid"];
    std::string hash = JMsg["hash"];
    doLogin(hdl, uid, hash);
}

void CampusLoginManager::handleRegister(websocketpp::connection_hdl hdl, json JMsg) {
    if (!JMsg.contains("uid") || !JMsg.contains("salt") || !JMsg.contains("hash")) {
        CampusLogger::warn("handleRegister: missing 'uid'/'salt'/'hash' in message");
        return;
    }
    std::string uid = JMsg["uid"];
    std::string salt = JMsg["salt"];
    std::string hash = JMsg["hash"];
    doRegister(hdl, uid, salt, hash);
}

void CampusLoginManager::handleLogout(websocketpp::connection_hdl hdl, const json JMsg) {
    if (!JMsg.contains("uid")) {
        CampusLogger::warn("handleLogout: missing 'uid' in message");
        return;
    }
    std::string uid = JMsg["uid"];
    doLogout(uid, hdl);
}

void CampusLoginManager::handleHdlClose(websocketpp::connection_hdl hdl) {
    // 清理断开的连接（遍历UID-连接映射）
    for (auto it = uid_hdl_map_.begin(); it != uid_hdl_map_.end();) {
        if (it->second.expired() || it->second.lock() == hdl.lock()) {
            CampusLogger::info("handleHdlClose: remove online uid={}", it->first);
            it = uid_hdl_map_.erase(it);
        } else {
            ++it;
        }
    }
}

// -------------------------- SQL结果回调接口实现（供WholeManager转发）--------------------------
void CampusLoginManager::onSelectSucess(std::vector<std::vector<std::pair<std::string, std::string>>>& result, CampusSqlInfo* userData) {
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_); // 智能指针管理内存，避免泄漏

    CampusLogger::info("CampusLoginManager: onSelectSucess");
    printLoginInfo(p_info);

    // 根据SQL操作类型分发处理
    switch (p_info->type) {
        case CampusLoginSqlType::LOGIN_SQL_SELECT_LOGIN_SALT:
            handleSelectLoginSalt(result, p_info);
            break;
        case CampusLoginSqlType::LOGIN_SQL_SELECT_LOGIN:
            handleSelectLogin(result, p_info);
            break;
        case CampusLoginSqlType::LOGIN_SQL_SELECT_REGISTER_INFO:
            handleSelectRegisterInfo(result, p_info);
            break;
        default:
            CampusLogger::warn("CampusLoginManager: unknown SQL select type");
            break;
    }
}

void CampusLoginManager::onSelectFail(CampusSqlInfo* userData) {
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_);
        
    CampusLogger::warn("CampusLoginManager: onSelectFail");
    printLoginInfo(p_info);
}

void CampusLoginManager::onInsertSucess(CampusSqlInfo* userData) {
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_);

    CampusLogger::info("CampusLoginManager: onInsertSucess");
    printLoginInfo(p_info);

    if (p_info->type == CampusLoginSqlType::LOGIN_SQL_INSERT_REGISTER_INFO) {
        handleInsertRegisterInfo(p_info);
    }
}

void CampusLoginManager::onInsertFail(CampusSqlInfo* userData) {
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_);

    CampusLogger::warn("CampusLoginManager: onInsertFail");
    printLoginInfo(p_info);

    // 注册失败：通知客户端
    if (p_info->type == CampusLoginSqlType::LOGIN_SQL_INSERT_REGISTER_INFO) {
        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_REGISTER;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::REGISTER_RET_EXIST);
        whole_server_->send(p_info->hdl, JMsg.dump());
    }
}

void CampusLoginManager::onUpdateSucess(CampusSqlInfo* userData)
{
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_);

    CampusLogger::info("CampusLoginManager: onUpdateSucess");

}

void CampusLoginManager::onUpdateFail(CampusSqlInfo* userData)
{
    CampusLoginInfo* p_info_ = dynamic_cast<CampusLoginInfo*>(userData);
    std::shared_ptr<CampusLoginInfo> p_info(p_info_);

    CampusLogger::warn("CampusLoginManager: onUpdateFail");
    printLoginInfo(p_info);
}


// -------------------------- 私有业务逻辑实现 --------------------------
void CampusLoginManager::doLoginSalt(websocketpp::connection_hdl hdl, const std::string& uid) {
    // 1. 构造SQL参数（参数化查询，避免注入）
    std::string sql = "SELECT salt FROM user_t WHERE uid = ?";
    std::vector<std::string> params = { uid };

    // 2. 构造业务数据载体
    CampusLoginInfo* p_info = new CampusLoginInfo();
    p_info->type = CampusLoginSqlType::LOGIN_SQL_SELECT_LOGIN_SALT;
    p_info->hdl = hdl;
    p_info->uid = uid;
    p_info->sql = sql;

    // 3. 调用SQL连接器执行查询
    sql_connector_->exec(sql, SELECT, params, static_cast<CampusSqlInfo*>(p_info));
}

void CampusLoginManager::doLogin(websocketpp::connection_hdl hdl, const std::string& uid, const std::string& hash) {
    // 1. 构造SQL参数（校验UID和加密后的密码）
    std::string sql = "SELECT * FROM user_t WHERE uid = ? AND hash = ?";
    std::vector<std::string> params = { uid, hash };

    // 2. 构造业务数据载体
    CampusLoginInfo* p_info = new CampusLoginInfo();
    p_info->type = CampusLoginSqlType::LOGIN_SQL_SELECT_LOGIN;
    p_info->hdl = hdl;
    p_info->uid = uid;
    p_info->hash = hash;
    p_info->sql = sql;

    // 3. 调用SQL连接器执行查询
    sql_connector_->exec(sql, SELECT, params, static_cast<CampusSqlInfo*>(p_info));
}

void CampusLoginManager::doRegister(websocketpp::connection_hdl hdl, const std::string& uid, const std::string& salt, const std::string& hash) {
    // 1. 先查询UID是否已存在（避免重复注册）
    std::string sql = "SELECT uid FROM user_t WHERE uid = ?";
    std::vector<std::string> params = { uid };

    // 2. 构造业务数据载体（携带注册所需的salt和hash）
    CampusLoginInfo* p_info = new CampusLoginInfo();
    p_info->type = CampusLoginSqlType::LOGIN_SQL_SELECT_REGISTER_INFO;
    p_info->hdl = hdl;
    p_info->uid = uid;
    p_info->salt = salt;
    p_info->hash = hash;
    p_info->sql = sql;

    // 3. 调用SQL连接器执行查询
    sql_connector_->exec(sql, SELECT, params, static_cast<CampusSqlInfo*>(p_info));
}

void CampusLoginManager::doLogout(const std::string& uid, websocketpp::connection_hdl hdl) {
    auto it = uid_hdl_map_.find(uid);
    if (it != uid_hdl_map_.end()) {
        // 登出成功：清理在线状态，通知客户端
        CampusLogger::info("doLogout: sucess, uid={}", uid);
        uid_hdl_map_.erase(it);

        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_LOGOUT;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::LOGOUT_RET_SUCCESS);
        whole_server_->send(hdl, JMsg.dump());
    } else {
        // 登出失败：用户未在线
        CampusLogger::warn("doLogout: fail, uid={} not online", uid);
        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_LOGOUT;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::LOGOUT_RET_FAIL);
        whole_server_->send(hdl, JMsg.dump());
    }
}

// -------------------------- SQL结果处理实现 --------------------------
void CampusLoginManager::handleSelectLoginSalt(std::vector<std::vector<std::pair<std::string, std::string>>>& result, std::shared_ptr<CampusLoginInfo> p_info) {
    if (result.empty()) {
        // UID不存在：通知客户端
        CampusLogger::info("handleSelectLoginSalt: uid={} not exist", p_info->uid);
        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_LOGIN_SALT;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::LOGIN_RET_NOT_EXIST);
        whole_server_->send(p_info->hdl, JMsg.dump());
    } else {
        // 获取Salt成功：返回Salt给客户端
        std::string salt = result[0][0].second;
        CampusLogger::info("handleSelectLoginSalt: sucess, uid={}, salt={}", p_info->uid, salt);
        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_LOGIN_SALT;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::LOGIN_RET_SALT_SUCCESS);
        JMsg["salt"] = salt;
        whole_server_->send(p_info->hdl, JMsg.dump());
    }
}

void CampusLoginManager::handleSelectLogin(std::vector<std::vector<std::pair<std::string, std::string>>>& result, std::shared_ptr<CampusLoginInfo> p_info) {
    if (result.empty()) {
        // 登录失败：UID或密码错误
        doLoginFail(p_info->hdl, p_info->uid);
    } else {
        // 登录成功：处理顶号、更新在线状态
        doLoginSucess(p_info->hdl, p_info->uid);
    }
}

void CampusLoginManager::handleSelectRegisterInfo(std::vector<std::vector<std::pair<std::string, std::string>>>& result, std::shared_ptr<CampusLoginInfo> p_info) {
    if (!result.empty()) {
        // UID已存在：通知客户端注册失败
        CampusLogger::warn("handleSelectRegisterInfo: uid={} already exist", p_info->uid);
        json JMsg;
        JMsg["cmd"] = SIGNAL_TYPE_RESP_REGISTER;
        JMsg["ret"] = static_cast<int>(CampusLoginRet::REGISTER_RET_EXIST);
        whole_server_->send(p_info->hdl, JMsg.dump());
    } else {
        // UID不存在：插入注册信息到数据库
        std::string sql = "INSERT INTO user_t(uid, salt, hash) VALUES(?, ?, ?)";
        std::vector<std::string> params = { p_info->uid, p_info->salt, p_info->hash };

        // 构造插入操作的业务数据载体
        CampusLoginInfo* p_insert_info = new CampusLoginInfo();
        p_insert_info->type = CampusLoginSqlType::LOGIN_SQL_INSERT_REGISTER_INFO;
        p_insert_info->hdl = p_info->hdl;
        p_insert_info->uid = p_info->uid;
        p_insert_info->salt = p_info->salt;
        p_insert_info->hash = p_info->hash;
        p_insert_info->sql = sql;

        // 执行插入
        sql_connector_->exec(sql, INSERT, params, static_cast<CampusSqlInfo*>(p_insert_info));
    }
}

void CampusLoginManager::handleInsertRegisterInfo(std::shared_ptr<CampusLoginInfo> p_info) {
    // 注册成功：通知客户端
    CampusLogger::info("handleInsertRegisterInfo: sucess, uid={}", p_info->uid);
    json JMsg;
    JMsg["cmd"] = SIGNAL_TYPE_RESP_REGISTER;
    JMsg["ret"] = static_cast<int>(CampusLoginRet::REGISTER_RET_SUCCESS);
    whole_server_->send(p_info->hdl, JMsg.dump());
}

// -------------------------- 辅助方法实现 --------------------------
void CampusLoginManager::printLoginInfo(const std::shared_ptr<CampusLoginInfo>& p_info) {
    CampusLogger::info("---------------------------- Login Info ----------------------------");
    CampusLogger::info("SQL: {}", p_info->sql);
    CampusLogger::info("Type: {}", static_cast<int>(p_info->type));
    CampusLogger::info("UID: {}", p_info->uid);
    CampusLogger::info("Salt: {}", p_info->salt);
    CampusLogger::info("Hash: {}", p_info->hash);
    CampusLogger::info("UserData: {:p}", p_info->user_data);
    CampusLogger::info("HDL: {:p}", p_info->hdl.lock().get());
    CampusLogger::info("---------------------------------------------------------------------");
}

void CampusLoginManager::doLoginSucess(websocketpp::connection_hdl hdl, const std::string& uid) {
    CampusLogger::info("doLoginSucess: uid={}", uid);

    // 1. 顶号处理：若用户已在线，强制下线旧连接
    auto it = uid_hdl_map_.find(uid);
    if (it != uid_hdl_map_.end()) {
        CampusLogger::info("doLoginSucess: uid={} already online, kick old connection", uid);
        // 通知旧客户端被顶号
        json kick_msg;
        kick_msg["cmd"] = SIGNAL_TYPE_RESP_LOGOUT;
        kick_msg["ret"] = static_cast<int>(CampusLoginRet::LOGOUT_RET_EXISTS);
        whole_server_->send(it->second, kick_msg.dump());
        // 移除旧连接映射
        uid_hdl_map_.erase(it);
    }

    // 2. 更新在线状态（添加新连接映射）
    uid_hdl_map_[uid] = hdl;

    // 3. 通知客户端登录成功
    json sucess_msg;
    sucess_msg["cmd"] = SIGNAL_TYPE_RESP_LOGIN;
    sucess_msg["ret"] = static_cast<int>(CampusLoginRet::LOGIN_RET_SUCCESS);
    whole_server_->send(hdl, sucess_msg.dump());
}

void CampusLoginManager::doLoginFail(websocketpp::connection_hdl hdl, const std::string& uid) {
    CampusLogger::warn("doLoginFail: uid={}", uid);
    // 通知客户端登录失败
    json fail_msg;
    fail_msg["cmd"] = SIGNAL_TYPE_RESP_LOGIN;
    fail_msg["ret"] = static_cast<int>(CampusLoginRet::LOGIN_RET_FAIL);
    whole_server_->send(hdl, fail_msg.dump());
}